package 多线程.FileSearch;
import java.io.File;
import java.util.Date;
import java.util.concurrent.ConcurrentLinkedQueue;
/*
* 1.Runtime.getRuntime().availableProcessors()获取CPU核心数  避免一个cpu开多个进程 然后切换导致性能降低
* 2.多线程做文件搜索有很多办法：
*   一：arraylist 每个线程分一定数量目录数，但是费内存空间，如果10个线程，就需要1+10个list存储空间--》1分成10
*   二：同样arraylist  但是不分配，通过加锁让线程自己抢  同样会影响性能
* 从而引出ConcurrentLinkedQueue
* ConcurrentLinkedQueue实际对应的是LinkedList,
* 是一个线程安全的无界队列，但LinkedList是一个双向链表，
* 而ConcurrentLinkedQueue是单向链表。
* ConcurrentLinkedQueue线程安全在于设置head、tail以及next指针时都用的cas操作，
* 而且node里的item和next变量都是用volatile修饰，保证了多线程下变量的可见性。
* 而ConcurrentLinkedQueue的所有读操作都是无锁的，所以可能读会存在不一致性
*3.现在是一个单向链表思路就好出来了，多线程poll自己拿就好了，剩下的大体跟 12 差不多。
* */

public class FileSearch {
    private static volatile boolean found = false; // 是否找到目标文件
    private static ConcurrentLinkedQueue<File> directoryQueue = new ConcurrentLinkedQueue<>(); // 待搜索目录队列
    //拿这个半AI生产算法跟老师的比较了一下，发现是要慢一半的，原因在于这个队列我是用的时候poll拿出来
    //后面是目录在offer进去，多了一个遍历目录的时间
    //跟老师的递归查找直接判断相比效率是要低的
    public static void main(String[] args) {
        String targetDirectory = "C:\\Windows\\"; // 设置根目录
        String targetFile = "hosts"; // 设置目标文件名
        Date start = new Date();
        File F = new File(targetDirectory);
        File[] files1 = F.listFiles();
        for(File f: files1){
            if (f.isDirectory()) {
                directoryQueue.offer(f);
            }else{
                if(f.getName().equals(targetFile)){
                    found = true;
                    Date end = new Date();
                    System.out.println("找到文件，位置在：" + f.getAbsolutePath());
                    System.out.printf("多线程花费时间: %d ms%n", end.getTime()-start.getTime());
                    return;
                }
            }
        }
        int numThreads = Runtime.getRuntime().availableProcessors(); // 获取CPU核心数
        // 初始化待搜索目录队列

        // 创建并启动多个搜索线程
        Thread[] searchThreads = new Thread[numThreads];
        for (int i = 0; i < numThreads; i++) {
            searchThreads[i] = new Thread(() -> {
                while (!found && !directoryQueue.isEmpty()) {
                    // 从目录队列中获取待搜索的目录
                    File directory = directoryQueue.poll();
                    if (directory == null) {
                        continue;
                    }
                    // 遍历当前目录下的所有文件和子目录
                    File[] files = directory.listFiles();
                    if (files != null) {
                        for (File file : files) {
                            if(Thread.currentThread().isInterrupted()){
                                System.out.println("其他线程已经找到了，线程"+(Thread.currentThread().getId()-19)+"停止");
                                return;
                            }
                            if (file.isDirectory()) {
                                // 如果是目录，将其加入目录队列中
                                directoryQueue.offer(file);
                            } else if (file.isFile() && file.getName().equals(targetFile)) {
                                // 如果找到目标文件，将found设置为true，中断其他线程
                                found = true;
                                Date end = new Date();
                                System.out.printf("多线程花费时间: %d ms%n", end.getTime()-start.getTime());
                                for (Thread t : searchThreads) {
                                    if (t != Thread.currentThread()) {
                                        t.interrupt();
                                    }
                                }
                                System.out.println("线程："+(Thread.currentThread().getId()-19)+"找到文件，位置：" + file.getAbsolutePath());
                                return;
                            }
                        }
                    }
                }
                System.out.println("线程："+(Thread.currentThread().getId()-19) + "跑完了");
            });
            searchThreads[i].start();
            System.out.println(searchThreads[i].getId()-19 + "线程开启");
        }

        // 循环检查线程状态，直到有一个线程已终止
        while (true) {
            boolean allThreadsTerminated = true;
            for (Thread t : searchThreads) {
                if (t.isAlive()) {
                    allThreadsTerminated = false;
                    break;
                }
            }

            if (allThreadsTerminated || found) {
                break;
            }
        }

        // 如果未找到目标文件
        if (!found) {
            Date end = new Date();
            System.out.printf("多线程花费时间: %d ms%n", end.getTime()-start.getTime());
            System.out.println("未找到目标文件");
        }else{
            System.out.println("找到了文件");
        }

    }
}